﻿@inherits Microsoft.VisualStudio.Web.CodeGeneration.Templating.RazorTemplateBase
@using System.Collections.Generic;
@using System.Linq;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.EntityFrameworkCore;
@{
    foreach (var namespaceName in Model.RequiredNamespaces)
    {
@:using @namespaceName;
    }
}

namespace @Model.ControllerNamespace
{
@{
    string routePrefix;
    if (String.IsNullOrEmpty(Model.AreaName))
    {
        routePrefix = Model.ControllerRootName;
    }
    else
    {
        routePrefix = Model.AreaName + "/" + Model.ControllerRootName;
    }
    var modelProperties = new List<string>();
    foreach (var property in Model.ModelMetadata.Properties)
    {
        if (property.Scaffold)
        {
            modelProperties.Add(property.PropertyName);
        }
    }
    var bindString = string.Join(",", modelProperties);
    var contextTypeName = Model.ContextTypeName;
    var entitySetName = Model.ModelMetadata.EntitySetName;
    var entitySetVar = Model.EntitySetVariable ??
        (String.IsNullOrEmpty(entitySetName)
            ? entitySetName
            : (entitySetName.Substring(0, length: 1).ToLowerInvariant() + entitySetName.Substring(1)));
    var primaryKeyName = Model.ModelMetadata.PrimaryKeys[0].PropertyName;
    var primaryKeyShortTypeName = Model.ModelMetadata.PrimaryKeys[0].ShortTypeName;
    var primaryKeyType = Model.ModelMetadata.PrimaryKeys[0].TypeName;
    var primaryKeyNullableTypeName = GetNullableTypeName(primaryKeyType, primaryKeyShortTypeName);
    var lambdaVar = Model.ModelVariable[0];
    var relatedProperties = new Dictionary<string, dynamic>();
    foreach (var nav in Model.ModelMetadata.Navigations)
    {
        relatedProperties.Add(nav.AssociationPropertyName, nav);

    }

    var inlineIncludes = "";
    foreach (var property in relatedProperties.Values)
    {
        inlineIncludes += string.Format("{0}                .Include({1} => {1}.{2})", Environment.NewLine, lambdaVar, property.AssociationPropertyName);
    }

    if (!string.IsNullOrEmpty(Model.AreaName))
    {
    @:@string.Format("[Area(\"{0}\")]", Model.AreaName)
    }
}
    public class @Model.ControllerName : Controller
    {
        private readonly @Model.ContextTypeName _context;

        public @(Model.ControllerName)(@Model.ContextTypeName context)
        {
            _context = context;
        }

        // GET: @routePrefix
@{
        @:public async Task<IActionResult> Index()
        @:{
    var includeExpressions = "";
    includeExpressions = String.Join("", relatedProperties
        .Values
        .Select(property => String.Format(".Include({0} => {0}.{1})", lambdaVar, property.AssociationPropertyName)));
    if (!String.IsNullOrEmpty(includeExpressions))
    {
            @:var @entitySetVar = _context.@entitySetName@includeExpressions;
            @:return View(await @(entitySetVar).ToListAsync());
    }
    else
    {
            @:return View(await _context.@(entitySetName).ToListAsync());
    }
}        }

        // GET: @routePrefix/Details/5
        public async Task<IActionResult> Details(@primaryKeyNullableTypeName id)
        {
            if (id == null)
            {
                return NotFound();
            }

            var @Model.ModelVariable = await _context.@(entitySetName)@inlineIncludes
                .FirstOrDefaultAsync(m => m.@primaryKeyName == id);
            if (@Model.ModelVariable == null)
            {
                return NotFound();
            }

            return View(@Model.ModelVariable);
        }

        // GET: @routePrefix/Create
        public IActionResult Create()
        {
@{
    foreach (var property in relatedProperties.Values)
    {
            @:ViewData["@(property.ForeignKeyPropertyNames[0])"] = new SelectList(_context.@property.EntitySetName, "@property.PrimaryKeyNames[0]", "@property.DisplayPropertyName");
    }
}            return View();
        }

        // POST: @routePrefix/Create
        // To protect from overposting attacks, enable the specific properties you want to bind to.
        // For more details, see http://go.microsoft.com/fwlink/?LinkId=317598.
        [HttpPost]
        [ValidateAntiForgeryToken]
        public async Task<IActionResult> Create([Bind("@bindString")] @Model.ModelTypeName @Model.ModelVariable)
        {
            if (ModelState.IsValid)
            {
@{
    if (!string.IsNullOrEmpty(primaryKeyType) && IsGuid(primaryKeyType))
    {
                @:@(Model.ModelVariable).@primaryKeyName = Guid.NewGuid();
    }
                @:_context.Add(@Model.ModelVariable);
                @:await _context.SaveChangesAsync();
}                return RedirectToAction(nameof(Index));
            }
@{
    foreach (var property in relatedProperties.Values)
    {
            @:ViewData["@(property.ForeignKeyPropertyNames[0])"] = new SelectList(_context.@property.EntitySetName, "@property.PrimaryKeyNames[0]", "@property.DisplayPropertyName", @(Model.ModelVariable).@property.ForeignKeyPropertyNames[0]);
    }
}
            return View(@Model.ModelVariable);
        }

        // GET: @routePrefix/Edit/5
        public async Task<IActionResult> Edit(@primaryKeyNullableTypeName id)
        {
            if (id == null)
            {
                return NotFound();
            }

            var @Model.ModelVariable = await _context.@(entitySetName).FindAsync(id);
            if (@Model.ModelVariable == null)
            {
                return NotFound();
            }
@{
    foreach (var property in relatedProperties.Values)
    {
            @:ViewData["@(property.ForeignKeyPropertyNames[0])"] = new SelectList(_context.@property.EntitySetName, "@property.PrimaryKeyNames[0]", "@property.DisplayPropertyName", @(Model.ModelVariable).@property.ForeignKeyPropertyNames[0]);
    }
}
            return View(@Model.ModelVariable);
        }

        // POST: @routePrefix/Edit/5
        // To protect from overposting attacks, enable the specific properties you want to bind to.
        // For more details, see http://go.microsoft.com/fwlink/?LinkId=317598.
        [HttpPost]
        [ValidateAntiForgeryToken]
        public async Task<IActionResult> Edit(@primaryKeyShortTypeName id, [Bind("@bindString")] @Model.ModelTypeName @Model.ModelVariable)
        {
            if (id != @Model.ModelVariable.@primaryKeyName)
            {
                return NotFound();
            }

            if (ModelState.IsValid)
            {
                try
                {
                    _context.Update(@Model.ModelVariable);
                    await _context.SaveChangesAsync();
                }
                catch (DbUpdateConcurrencyException)
                {
                    if (!@(Model.ModelTypeName)Exists(@Model.ModelVariable.@primaryKeyName))
                    {
                        return NotFound();
                    }
                    else
                    {
                        throw;
                    }
                }
                return RedirectToAction(nameof(Index));
            }
@{
    foreach (var property in relatedProperties.Values)
    {
            @:ViewData["@(property.ForeignKeyPropertyNames[0])"] = new SelectList(_context.@property.EntitySetName, "@property.PrimaryKeyNames[0]", "@property.DisplayPropertyName", @(Model.ModelVariable).@property.ForeignKeyPropertyNames[0]);
    }
}
            return View(@Model.ModelVariable);
        }

        // GET: @routePrefix/Delete/5
        public async Task<IActionResult> Delete(@primaryKeyNullableTypeName id)
        {
            if (id == null)
            {
                return NotFound();
            }

            var @Model.ModelVariable = await _context.@(entitySetName)@inlineIncludes
                .FirstOrDefaultAsync(m => m.@primaryKeyName == id);
            if (@Model.ModelVariable == null)
            {
                return NotFound();
            }

            return View(@Model.ModelVariable);
        }

        // POST: @routePrefix/Delete/5
        [HttpPost, ActionName("Delete")]
        [ValidateAntiForgeryToken]
        public async Task<IActionResult> DeleteConfirmed(@primaryKeyShortTypeName id)
        {
            var @Model.ModelVariable = await _context.@(entitySetName).FindAsync(id);
            _context.@(entitySetName).Remove(@Model.ModelVariable);
            await _context.SaveChangesAsync();
            return RedirectToAction(nameof(Index));
        }

        private bool @(Model.ModelTypeName)Exists(@primaryKeyShortTypeName id)
        {
            return _context.@(entitySetName).Any(e => e.@primaryKeyName == id);
        }
    }
}
@functions
{
    // This function converts the primary key short type name to its nullable equivalent when possible. This is required to make
    // sure that an HTTP 400 error is thrown when the user tries to access the edit, delete, or details action with null values.
    string GetNullableTypeName(string typeName, string shortTypeName)
    {
        // The exceptions are caught because if for any reason the type is user defined, then the short type name will be used.
        // In that case the user will receive a server error if null is passed to the edit, delete, or details actions.
        Type primaryKeyType = null;
        try
        {
            primaryKeyType = Type.GetType(typeName);
        }
        catch
        {
        }
        if (primaryKeyType != null && (!Microsoft.VisualStudio.Web.CodeGeneration.Templating.TypeUtilities.IsNullable(primaryKeyType) || IsGuid(typeName)))
        {
            return shortTypeName + "?";
        }
        return shortTypeName;
    }

    bool IsGuid(string typeName) {
        return String.Equals("System.Guid", typeName, StringComparison.OrdinalIgnoreCase);
    }
}
